package com.deram.ctin.serv.third.api.impl;

import com.deram.ctin.common.cache.CacheManage;
import com.deram.ctin.common.consts.CacheConsts;
import com.deram.ctin.common.error.BusinessException;
import com.deram.ctin.common.utils.DateUtils;
import com.deram.ctin.common.utils.ValidateUtils;
import com.deram.ctin.serv.third.api.CaptchaApi;
import com.deram.ctin.serv.third.prop.CaptchaProp;
import com.deram.ctin.serv.third.vo.CaptchaInfo;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class CaptchaApiImpl implements CaptchaApi {

    private static final String HISTORY_KEY = CacheConsts.PREV_CAPTCHA + "HISTORY_";

    @Autowired
    private CaptchaProp captchaProp;

    @Autowired
    private CacheManage cacheManage;

    @Override
    public String create(String key) {
        checkKey(key);
        return createCaptcha(key);
    }

    @Override
    public void verify(String key, String captcha) {
        checkCaptcha(key, captcha);
        clearCaptcha(key);
    }

    private void checkKey(String key){
        ValidateUtils.notEmpty(key, "验证码key");
        // 生成间隔检测
        Integer createIntervalTime = captchaProp.getCreateIntervalTime();
        if(createIntervalTime > 0){
            List<CaptchaInfo> list = listHistoryByKey(key, createIntervalTime);
            if(list.size() > 0){
                throw new BusinessException("验证码生成间隔不能小于" + (createIntervalTime / 60) + "分钟");
            }
        }
        // 一段时间内可生成短信的次数检测
        Integer createCycleTime = captchaProp.getCreateCycleTime();
        Integer createCycleCount = captchaProp.getCreateCycleCount();
        if(createCycleTime > 0 && createCycleCount > 0){
            List<CaptchaInfo> list = listHistoryByKey(key, createCycleTime);
            if(list.size() >= createCycleCount){
                throw new BusinessException((createCycleTime / 60) + "分钟内，验证码生成次数不能超过" + createCycleCount + "次");
            }
        }
        // 检查一天最多生成条数
        Integer createMaxCount = captchaProp.getCreateMaxCount();
        if(createMaxCount > 0){
            List<CaptchaInfo> list = listHistoryByKey(key, null);
            if(list.size() >= createMaxCount){
                throw new BusinessException("验证码生成次数已超出最大生成次数(一天最多" + createMaxCount + "次)");
            }
        }
    }

    private String createCaptcha(String key){
        String captcha = captchaProp.getAlwaysCaptcha();
        if(StringUtils.isBlank(captcha)){
            captcha = RandomStringUtils.randomNumeric(6);
        }
        cacheManage.put(CacheConsts.PREV_CAPTCHA, key, captcha, captchaProp.getCaptchaExpireTime());
        addHistoryByKey(key);
        return captcha;
    }

    private void checkCaptcha(String key, String captcha){
        ValidateUtils.notEmpty(key, "验证码key");
        ValidateUtils.notEmpty(captcha, "验证码");
        String cacheCaptcha = (String) cacheManage.get(CacheConsts.PREV_CAPTCHA, key);
        if(StringUtils.isBlank(cacheCaptcha)){
            throw new BusinessException("验证码已失效");
        }
        if(!cacheCaptcha.equals(captcha)){
            throw new BusinessException("验证码错误");
        }
    }

    private void clearCaptcha(String key){
        cacheManage.clear(CacheConsts.PREV_CAPTCHA, key);
    }

    private List<CaptchaInfo> listHistoryByKey(String key, Integer periodTime){
        List<CaptchaInfo> periodList = Lists.newArrayList();
        List<CaptchaInfo> allList = cacheManage.get(HISTORY_KEY, key);
        if(CollectionUtils.isEmpty(allList)){
            return periodList;
        }
        for (CaptchaInfo obj : allList) {
            Long createTime = obj.getCreateTime().getTime();

            if(createTime < DateUtils.getNowDateLong()){
                continue;
            }
            if(null != periodTime){
                Long t = (DateUtils.getNowLong() - createTime) / 1000;
                if(t > periodTime){
                    continue;
                }
            }
            periodList.add(obj);
        }
        return periodList;
    }

    private void addHistoryByKey(String key){
        List<CaptchaInfo> list = cacheManage.get(HISTORY_KEY, key);
        if(CollectionUtils.isEmpty(list)){
            list = Lists.newArrayList();
        }
        List<CaptchaInfo> delList = Lists.newArrayList();
        for (CaptchaInfo obj : list) {
            Long createTime = obj.getCreateTime().getTime();
            if(createTime > DateUtils.getNowDateLong()){
                continue;
            }
            delList.add(obj);
        }
        list.removeAll(delList);
        CaptchaInfo captchaInfo = new CaptchaInfo();
        captchaInfo.setCaptcha(key);
        captchaInfo.setCreateTime(DateUtils.getNow());
        list.add(captchaInfo);
        cacheManage.put(HISTORY_KEY, key, list, captchaProp.getHistoryExpireTime());
    }
}
